/*
	Voxel Type 1
*/

#include "common.cl"

enum EVoxelType
{
	BORDER = 0,		// border voxel
	EMPTY,
	WATER,
	SAND,
	STONE,
	GROUND,
};

typedef struct _Voxel
{
	float3	force;
	float	density;	// mass = density * voxel volume
	int		type;		// EVoxelType
	int		__align[3];	// align for multiple of 16 bytes
} Voxel;

enum
{
	Voxel_PixelPerVoxel = sizeof(Voxel) / sizeof(VOXEL_TEXTURE_DATA_TYPE),
};

static_assert( Voxel_PixelPerVoxel == PIXEL_PER_VOXEL, "invalid " );


union TextureVoxelData
{
	Voxel					voxel;
	VOXEL_TEXTURE_DATA_TYPE	data[ PIXEL_PER_VOXEL ];
};


__constant sampler_t g_defaultVoxelTextureSampler = CLK_FILTER_NEAREST | CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE;


Voxel InitVoxel ()
{
	Voxel v;
	v.force		= (float3)(0.0);
	v.density	= 1.0;
	v.type		= SAND;
	return v;
}


Voxel ReadVoxel (read_only image2d_t image, int2 coord)
{
	union TextureVoxelData vd;

	#pragma unroll
	for (int i = 0; i < PIXEL_PER_VOXEL; ++i)
	{
		vd.data[i] = read_imagei( image, g_defaultVoxelTextureSampler, coord + (int2)(i, 0) );
	}

	return vd.voxel;
}


void ReadVoxels9 (read_only image2d_t image, int3 center, Voxel voxels[_VOX_COUNT_3D])
{
	#pragma unroll
	for (int z = -_BORDER_SIZE; z <= _BORDER_SIZE; ++z)
	{
		#pragma unroll
		for (int y = -_BORDER_SIZE; y <= _BORDER_SIZE; ++y)
		{
			#pragma unroll
			for (int x = -_BORDER_SIZE; x <= _BORDER_SIZE; ++x)
			{
				const int	i = XYZ_TO_I( x, y, z );
				const int2	c = GetTexCoord( center + (int3)( x, y, z ) );
				
				voxels[i] = ReadVoxel( image, c );
			}
		}
	}
}


void WriteVoxel (write_only image2d_t image, int2 coord, Voxel voxel)
{
	union TextureVoxelData vd;
	vd.voxel = voxel;

	#pragma unroll
	for (int i = 0; i < PIXEL_PER_VOXEL; ++i)
	{
		write_imagei( image, coord, vd.data[i] );
	}
}
